﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CmdInplaceEditNameDefines.h"
#include "GmUiInplaceEditCommandRegister.h"
#include "EditFamilySharedContent.h"
#include "GmCommunicationProtocolUtils.h"
#include "UiInplaceEditModeUtil.h"
#include "ComponentEditProjectState.h"
#include "SocketPortConfig.h"
#include "GbmpCommandBase.h"
#include "GbmpFileSystem.h"
#include "GmProcessServer.h"
#include "CmdStatusUtils.h"

// 平台头文件
#include "IDocument.h"
#include "IFamilyConfigElement.h"
#include "CommandParameters.h"


#include "FilePath.h"
#include "UiCommonDialog.h"
#include "DocumentPathUtils.h"

#include "UiDocumentViewUtils.h"
#include "QProcess"
#include "JournalUtils.h"
#include "FilePathManager.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

namespace
{
    namespace
    {
        //////////////////////////////////////////////////////////////////////////

        class QDetachableProcess : public QProcess
        {
        public:
            QDetachableProcess(QObject *parent = nullptr);
            bool detach();
        };

        QDetachableProcess::QDetachableProcess(QObject *parent) : QProcess(parent)
        {
        }

        bool QDetachableProcess::detach()
        {

            setProcessState(QProcess::NotRunning);
            return true;
        }
    }

    bool StartFamilyEditor()
    {
        // 启动族App
        uint16_t port = ProcessServer::GetInstance()->GetPort();
        std::wstring familyAppPath = L"\"" + FilePath::Combine(FileSystem::GetExeDirPath(), UiInplaceEditModeUtil::GetFamilyEditorAppName() + L".exe\"");
        familyAppPath += L" -ReadyRecieverPort" + StringUtil::ToWString(port) 
            + L" -ReadyRecieverFunctionType" + StringUtil::ToWString((int)FunctionType::EditFamily);

        if (JournalUtils::IsInReplay())
        {
            // 回放时会有单独的（非全局唯一）的端口配置
            SocketPortConfigRecord appRecord(ProcessServer::GetInstance()->GetServerGuid(), port, UiInplaceEditModeUtil::GetAppName());
            SocketPortConfig::CreateJournalReplayEnvironment(appRecord);

            // 回放时允许弹出多个构件编辑器
            familyAppPath += L" -IsNotSingleton -InReplay";
            // 回放时将构件编辑器脚本和主进程脚本放在一起
            std::wstring logsFolderPath = FilePathManager::Get()->GetLogsFolderPath().GetFullPath();
            std::wstring logFolderPath = LogManager::Get()->GetLogsFolder();
            std::wstring logFolderName = logFolderPath.substr(int(logsFolderPath.length()), GbmpString::npos);// 这里拿到的其实是相对于“Log”目录的路径
            familyAppPath += L" /LogFolderName:" + logFolderName;
        }
        else
        {
            familyAppPath += L" -ForceSingleton";
        }

        QDetachableProcess detachProcess;
        detachProcess.start(QString::fromStdWString(familyAppPath));
        if (!detachProcess.waitForReadyRead())
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"警告"), GBMP_TR(L"构件编辑器启动失败！"), (int)UiCommonDialog::ButtonType::OK);
            return false;
        }
        detachProcess.detach();
        return true;
    }
}
class CmdEditFamilyCrossProcess : public GbmpCommandBase
{
public:
    CmdEditFamilyCrossProcess()
        : GbmpCommandBase(ID_CMD_EDIT_FAMILY_CROSS_PROCESS)
    {}

    // 实现ICommand接口
public:
    virtual OwnerPtr<IAction> ExecuteCommand(const gcmp::CommandParameters& cmdParams) override;

    virtual bool IsEnabled() const override { CMD_ONLY_ENABLE_IN_PROJECT_ENVIRONMENT }
    virtual bool IsVisible() const override { CMD_ONLY_ENABLE_IN_PROJECT_ENVIRONMENT }

private: 
    
};


OwnerPtr<IAction> CmdEditFamilyCrossProcess::ExecuteCommand(const gcmp::CommandParameters &cmdParams)
{
    if ((int)cmdParams.size() != 2 || cmdParams.find(L"FamilyName") == cmdParams.end())
        return nullptr;

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"无效的pDoc指针",L"GDMPLab",L"2024-03-30");
    std::wstring sFamilyName = cmdParams.at(L"FamilyName").AsWString();
    const IFamilyConfigElement* pElement = IFamilyConfigElement::GetFamilyConfigElementByName(pDoc, sFamilyName);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElement, L"对应FamilyConfigItem不存在",L"GDMPLab",L"2024-03-30");
    std::wstring familyFilePath = pElement->GetFamilyFilePath(pDoc);

    // 共享数据的生成
    OwnerPtr<EditFamilySharedContent> opEditFamilySharedContent = NEW_AS_OWNER_PTR(EditFamilySharedContent);
    opEditFamilySharedContent->SetMainServiceGuid(GuidUtils::ToString(ProcessServer::GetInstance()->GetServerGuid()));
    opEditFamilySharedContent->SetMainDocumentPath(DocumentPathUtils::GetTempDirectoryPath(pDoc));
    opEditFamilySharedContent->SetEditFamilyFilePath(familyFilePath);
    opEditFamilySharedContent->SetFamilyName(sFamilyName);

    // 查找族App端口
    std::vector<SocketPortConfigRecord> records;
    bool isOk = SocketPortConfig::GetAppRecords(UiInplaceEditModeUtil::GetFamilyEditorAppName(), records);
    if (!isOk || records.empty())
    {
        if (!StartFamilyEditor())
        {
            return nullptr;
        }
        ComponentEditProjectState::Get()->SetEditFamilySharedContent(TransferOwnership(opEditFamilySharedContent));
    }
    else
    {
        CommunicationProtocolUtils::SendIpcMessage(records.front().m_port, FunctionType::EditFamily, OperationType::StartEditByCopy, opEditFamilySharedContent.get());
    }

    return nullptr;
}

REGISTER_GM_COMMAND(CmdEditFamilyCrossProcess);
